package com.mallcai.bigdata.ladon.utils;

import com.mallcai.bigdata.ladon.dpl.vo.DataType;
import org.apache.commons.lang3.StringUtils;

import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.Calendar;
import java.util.Date;

/**
 * described :
 * Created by CaKeDou on 2016-10-25 17:54.
 * Modify:
 */
public class DateUtils {
    /**
     * yyyy-MM-dd hh:mm:ss
     */
    public static final String DATE_FORMAT        = "yyyyMMdd_HH:mm:ss";
    public static final String NORMAL_DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";
    public static final String DATE_FORMAT_DATE   = "yyyy-MM-dd";
    public static final String DATE_MONTH         = "yyyy-MM";
    public static final String DATE_YEAR          = "yyyy";
    public static final String DATE_STRICT_FORMAT = "yyyyMMddHHmmss";
    public static final String DATE_STRICT_MONTH  = "yyyyMM";
    public static final String DATE_STRICT_DATE   = "yyyyMMdd";

    public static final Long ONE_DAY_MILLISECOND = 86400000L;

    public static String getCurrentTime(String format) {
        return formatDate(new Date(), format);
    }

    /**
     * 获取日期格式字符串: yyyy-MM-dd
     *
     * @return String , 例如:2016-09-12
     */
    public static String getCurrentDate() {
        return getCurrentTime(DATE_FORMAT_DATE);
    }

    public static String getCurrentTime() {
        return getCurrentTime(DateUtils.DATE_FORMAT);
    }

    private static SimpleDateFormat getFormat(String format) {
        if (format == null || "".equals(format)) {
            format = DateUtils.DATE_FORMAT;
        }
        return new SimpleDateFormat(format);
    }

    /**
     * 将字段串转换成Date类型
     *
     * @param dateStr String 时间字段串
     * @param format  String 格式
     * @return Date
     */
    public static Date parseDate(String dateStr, String format) {
        if (StringUtils.isBlank(dateStr) || StringUtils.isBlank(format)) {
            return null;
        }

        SimpleDateFormat sdf = new SimpleDateFormat(format);
        try {
            return sdf.parse(dateStr);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 格式化时间
     *
     * @param date   Date
     * @param format String
     * @return String
     */
    public static String formatDate(Date date, String format) {
        if (date == null) {
            return "";
        }
        SimpleDateFormat sdf = getFormat(format);
        return sdf.format(date);
    }

    public static String formatDate(Long timestamp, String format) {
        return formatDate(new Date(timestamp), format);
    }

    /**
     * 将时间日期格式化为:yyyy-MM-dd形式
     * 转换失败时返回null
     *
     * @param date Date
     * @return String
     */
    public static String formatDate(Date date) {
        return formatDate(date, DATE_FORMAT_DATE);
    }

    /**
     * 获取当年的第一天
     *
     * @return Date
     */
    public static Date getCurrYearFirst() {
        Calendar currCal = Calendar.getInstance();
        int currentYear = currCal.get(Calendar.YEAR);
        return getYearFirst(currentYear);
    }

    /**
     * 获取某年第一天日期
     *
     * @param year 年份
     * @return Date
     */
    public static Date getYearFirst(int year) {
        Calendar calendar = Calendar.getInstance();
        calendar.clear();
        calendar.set(Calendar.YEAR, year);
        return calendar.getTime();
    }

    /**
     * 增加天数,可为负值,代表减少天数
     *
     * @param date   Date
     * @param amount int
     * @return Date
     */
    public static Date addDays(final Date date, final int amount) {
        return add(date, Calendar.DAY_OF_MONTH, amount);
    }

    /**
     * 增加月数,可为负值,代表减少月
     *
     * @param date   Date
     * @param amount int
     * @return Date
     */
    public static Date addMonths(final Date date, final int amount) {
        return add(date, Calendar.MONTH, amount);
    }

    /**
     * 增加年数,可为负值,代表减少年
     *
     * @param date   Date
     * @param amount int
     * @return Date
     */
    public static Date addYears(final Date date, final int amount) {
        return add(date, Calendar.MONTH, amount * 12);
    }

    private static Date add(final Date date, final int calendarField, final int amount) {
        if (date == null) {
            throw new IllegalArgumentException("The date must not be null");
        }
        final Calendar c = Calendar.getInstance();
        c.setTime(date);
        c.add(calendarField, amount);
        return c.getTime();
    }

    /**
     * 获取指定加减天数
     *
     * @param n n
     * @return String
     */
    public static String getNdaysBeforeToday(int n) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(new Date());  //today
        cal.add(Calendar.DATE, -n);
        Date time = cal.getTime();
        return new SimpleDateFormat("yyyy-MM-dd").format(time);
    }

    /**
     * 获取本周开始日期
     */
    public static String getThisWeekStartDay() {
        Calendar cal = Calendar.getInstance();
        cal.setTime(new Date());  //today
        Integer dayOfWeek = cal.get(Calendar.DAY_OF_WEEK);
        if (dayOfWeek == 1) {  //周日
            return getNdaysBeforeToday(6);
        }
        return getNdaysBeforeToday(dayOfWeek - 2);
    }

    /**
     * 获取上周开始日期
     *
     * @return String
     */
    public static String getLastWeekStartDay() {
        Calendar cal = Calendar.getInstance();
        cal.setTime(new Date());  //today
        Integer dayOfWeek = cal.get(Calendar.DAY_OF_WEEK);
        if (dayOfWeek == 1) {  //周日
            return getNdaysBeforeToday(6 + 7);
        }
        return getNdaysBeforeToday(dayOfWeek - 2 + 7);
    }

    /**
     * 获取上周结束日期
     *
     * @return String
     */
    public static String getLastWeekEndDay() {
        Calendar cal = Calendar.getInstance();
        cal.setTime(new Date());  //today
        Integer dayOfWeek = cal.get(Calendar.DAY_OF_WEEK);
        if (dayOfWeek == 1) {  //周日
            return getNdaysBeforeToday(7);
        }
        return getNdaysBeforeToday(dayOfWeek - 1);
    }

    /**
     * 获取某天的结束时间字符串
     *
     * @param day int 0 表示当天; -1 昨天 1 明天 , 以些类推
     * @param dt  DataType
     * @return String
     */
    public static String getEndDay(int day, DataType dt) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(new Date());  //today
        cal.add(Calendar.DAY_OF_MONTH, day);

        cal.set(Calendar.HOUR_OF_DAY, 23);
        cal.set(Calendar.MINUTE, 59);
        cal.set(Calendar.MILLISECOND, 59);
        if (dt == DataType.DATE) {
            return new SimpleDateFormat(DATE_FORMAT_DATE).format(cal.getTime());
        } else if (dt == DataType.DATETIME) {
            return new SimpleDateFormat(NORMAL_DATE_FORMAT).format(cal.getTime());
        }
        return null;
    }

    /**
     * 获取某天的开始时间字符串
     *
     * @param day int 0 表示当天; -1 昨天 1 明天 , 以些类推
     * @param dt  DataType
     * @return String
     */
    public static String getStartDay(int day, DataType dt) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(new Date());  //today
        cal.add(Calendar.DAY_OF_MONTH, day);
        cal.set(Calendar.HOUR_OF_DAY, 0);
        cal.set(Calendar.MINUTE, 0);
        cal.set(Calendar.MILLISECOND, 0);
        if (dt == DataType.DATE) {
            return new SimpleDateFormat(DATE_FORMAT_DATE).format(cal.getTime());
        } else if (dt == DataType.DATETIME) {
            return new SimpleDateFormat(NORMAL_DATE_FORMAT).format(cal.getTime());
        }
        return null;
    }

    /**
     * 获取本月开始日期
     *
     * @return String
     */
    public static String getThisMonthStartDay() {
        Calendar cal = Calendar.getInstance();
        cal.add(Calendar.MONTH, 0);
        cal.set(Calendar.DAY_OF_MONTH, 1);//设置为1号,当前日期既为本月第一天
        Date time = cal.getTime();
        return new SimpleDateFormat("yyyy-MM-dd").format(time);
    }

    /**
     * 获取上月开始日期
     *
     * @return String
     */
    public static String getLastMonthStartDay() {
        Calendar cal = Calendar.getInstance();
        cal.add(Calendar.MONTH, -1);
        cal.set(Calendar.DAY_OF_MONTH, 1);//设置为1号,当前日期既为上月第一天
        Date time = cal.getTime();
        return new SimpleDateFormat("yyyy-MM-dd").format(time);
    }

    /**
     * 获取上月结束日期
     *
     * @return String
     */
    public static String getLastMonthEndDay() {
        Calendar cal = Calendar.getInstance();
        cal.add(Calendar.MONTH, 0);
        cal.set(Calendar.DAY_OF_MONTH, 1);//设置为1号,当前日期既为本月第一天
        cal.add(Calendar.DATE, -1);  //本月第一天减一天就是上月最后一天
        Date time = cal.getTime();
        return new SimpleDateFormat("yyyy-MM-dd").format(time);
    }

    /**
     * 获取本季度开始日期
     */
    public static String getThisQuarterStartDay() {
        Calendar c = Calendar.getInstance();
        int currentMonth = c.get(Calendar.MONTH) + 1;
        if (currentMonth >= 1 && currentMonth <= 3) {
            c.set(Calendar.MONTH, 0);
        } else if (currentMonth >= 4 && currentMonth <= 6) {
            c.set(Calendar.MONTH, 3);
        } else if (currentMonth >= 7 && currentMonth <= 9) {
            c.set(Calendar.MONTH, 6);
        } else if (currentMonth >= 10 && currentMonth <= 12) {
            c.set(Calendar.MONTH, 9);
        }
        c.set(Calendar.DATE, 1);
        return new SimpleDateFormat("yyyy-MM-dd").format(c.getTime());
    }

    /**
     * 获取上季度开始日期
     */
    public static String getLastQuarterStartDay() {
        Calendar c = Calendar.getInstance();
        int currentYear = c.get(Calendar.YEAR);

        int currentMonth = c.get(Calendar.MONTH) + 1;
        if (currentMonth >= 1 && currentMonth <= 3) {
            c.set(Calendar.MONTH, 9);  //去年的第4季度
            c.set(Calendar.YEAR, currentYear - 1);
        } else if (currentMonth >= 4 && currentMonth <= 6) {
            c.set(Calendar.MONTH, 0);
        } else if (currentMonth >= 7 && currentMonth <= 9) {
            c.set(Calendar.MONTH, 3);
        } else if (currentMonth >= 10 && currentMonth <= 12) {
            c.set(Calendar.MONTH, 6);
        }
        c.set(Calendar.DATE, 1);
        return new SimpleDateFormat("yyyy-MM-dd").format(c.getTime());
    }

    /**
     * 获取上季度结束日期
     */
    public static String getLastQuarterEndDay() {
        Calendar c = Calendar.getInstance();
        int currentMonth = c.get(Calendar.MONTH) + 1;
        if (currentMonth >= 1 && currentMonth <= 3) {
            c.set(Calendar.MONTH, 0);
        } else if (currentMonth >= 4 && currentMonth <= 6) {
            c.set(Calendar.MONTH, 3);
        } else if (currentMonth >= 7 && currentMonth <= 9) {
            c.set(Calendar.MONTH, 6);
        } else if (currentMonth >= 10 && currentMonth <= 12) {
            c.set(Calendar.MONTH, 9);
        }
        c.set(Calendar.DATE, 1);
        //本季度第一天减去1天
        c.add(Calendar.DATE, -1);
        return new SimpleDateFormat("yyyy-MM-dd").format(c.getTime());
    }

    /**
     * 获取本年开始日期
     */
    public static String getThisYearStartDay() {
        Calendar c = Calendar.getInstance();
        int currentYear = c.get(Calendar.YEAR);
        c.set(Calendar.YEAR, currentYear);
        c.set(Calendar.MONTH, 0);
        c.set(Calendar.DATE, 1);
        return new SimpleDateFormat("yyyy-MM-dd").format(c.getTime());
    }

    /**
     * 获取去年开始日期
     */
    public static String getLastYearStartDay() {
        Calendar c = Calendar.getInstance();
        int currentYear = c.get(Calendar.YEAR);
        c.set(Calendar.YEAR, currentYear - 1);
        c.set(Calendar.MONTH, 0);
        c.set(Calendar.DATE, 1);
        return new SimpleDateFormat("yyyy-MM-dd").format(c.getTime());
    }

    /**
     * 获取去年结束日期
     */
    public static String getLastYearEndDay() {
        Calendar c = Calendar.getInstance();
        int currentYear = c.get(Calendar.YEAR);
        c.set(Calendar.YEAR, currentYear);
        c.set(Calendar.MONTH, 0);
        c.set(Calendar.DATE, 1);
        //今年开始日期减1天
        c.add(Calendar.DATE, -1);
        return new SimpleDateFormat("yyyy-MM-dd").format(c.getTime());
    }

    /**
     * 获取昨日日期中文格式
     */
    public static String getYesterdayZh() {
        return getYesterday("yyyy年MM月dd日");
    }


    /**
     * 获取昨日日期
     *
     * @param formatter String 指定格式, 例如: yyyy-MM-dd
     */
    public static String getYesterday(String formatter) {
        return formatDate(addDays(new Date(), -1), formatter);
    }

    /**
     * 获取昨日周几
     */
    public static String getYesterdayWeek() {
        Calendar c = Calendar.getInstance();
        c.setTime(addDays(new Date(), -1));
        int weekDay = c.get(Calendar.DAY_OF_WEEK);
        String ret = "";
        switch (weekDay) {
            case 1:
                ret = "周日";
                break;
            case 2:
                ret = "周一";
                break;
            case 3:
                ret = "周二";
                break;
            case 4:
                ret = "周三";
                break;
            case 5:
                ret = "周四";
                break;
            case 6:
                ret = "周五";
                break;
            case 7:
                ret = "周六";
                break;
            default:
                ret = "";
                break;
        }
        return ret;
    }

    public static int getDayOfMonth() {
        Calendar c = Calendar.getInstance();
        c.setTime(new Date());
        return c.get(Calendar.DAY_OF_MONTH);
    }

    /**
     * 输入日期字符串，返回当月第一天的Date
     */
    public static String getMinDateMonth(String month) {
        try {
            SimpleDateFormat sdf = new SimpleDateFormat(DATE_STRICT_MONTH);
            Date nowDate = sdf.parse(month);
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(nowDate);
            calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMinimum(Calendar.DAY_OF_MONTH));
            Date date = calendar.getTime();
            sdf = new SimpleDateFormat(DATE_FORMAT_DATE);
            return sdf.format(date);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 输入日期字符串，返回当月最后一天的Date
     */
    public static String getMaxDateMonth(String month) {
        try {
            SimpleDateFormat sdf = new SimpleDateFormat(DATE_STRICT_MONTH);
            Date nowDate = sdf.parse(month);
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(nowDate);
            calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMaximum(Calendar.DAY_OF_MONTH));
            Date date = calendar.getTime();
            sdf = new SimpleDateFormat(DATE_FORMAT_DATE);
            return sdf.format(date);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 判断时间字符串是否为有效的
     *
     * @param str       String 时间字符串
     * @param formatStr String 格式如:"yyyy-MM-dd"
     * @return boolean
     */
    public static boolean isValidDate(String str, String formatStr) {
        boolean convertSuccess = true;
        try {
            SimpleDateFormat format = new SimpleDateFormat(formatStr);

            // 设置lenient为false.
            // 否则SimpleDateFormat会比较宽松地验证日期，比如2007/02/29会被接受，并转换成2007/03/01
            format.setLenient(false);
            format.parse(str);
        } catch (Exception e) {
            convertSuccess = false;
        }
        return convertSuccess;
    }

    public static long getDateFromDays(Double dateValue) {
        return new Double(dateValue * ONE_DAY_MILLISECOND).longValue();
    }

    public static LocalDateTime atEndOfDay(LocalDateTime localDateTime){
        return localDateTime.withHour(23).withMinute(59).withSecond(59);
    }

    public static LocalDateTime atStartOfDay(LocalDateTime localDateTime){
        return localDateTime.toLocalDate().atStartOfDay();
    }

    public static LocalDateTime atStartOfHour(LocalDateTime localDateTime){
        return localDateTime.withMinute(0).withSecond(0);
    }
    public static LocalDateTime atEndOfHour(LocalDateTime localDateTime){
        return localDateTime.withMinute(59).withSecond(59);
    }


    public static long convert2MilliSec(LocalDateTime localDateTime){
        return localDateTime.toInstant(ZoneOffset.of("+8")).toEpochMilli();
    }

}
